#include <cstddef>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "napi/native_api.h"
#include "hilog/log.h"

#define LOG_DOMAIN 0x0201
#define LOG_TAG "MY_TAG"
#define BUFFER_SIZE 1024


struct interface{
    bool is_set = false;
    int rx = -1;
    int tx = -1;
    char name[32];
    char gateway[32];
    char hwaddr[32];
    char ipv4[32];
    char ipv6[32];
    interface* next = NULL;
};

interface* iface_head = NULL;
interface* iface_select = NULL;

void set_interface(interface* iface);

void init_interface(const char* iface_name){
    iface_select = iface_head;
    while (iface_select != NULL) {
        if (!strcmp(iface_select->name, iface_name)){
            set_interface(iface_select);
            break;
        }
        
        iface_select = iface_select->next;
    }
}

void free_iface() {
    interface* iface_cur = iface_head;
    interface* iface_tofree = iface_cur;
    iface_head = NULL;
    while (iface_cur) {
        iface_cur = iface_cur->next;
        delete(iface_tofree);
        iface_tofree = iface_cur;
    }
}

// 执行命令并返回输出
char* execute_command(const char* command) {
    FILE* fp = popen(command, "r");
    if (fp == NULL) {
        perror("popen failed");
        return NULL;
    }

    char* output = (char*) malloc(BUFFER_SIZE);
    if (output == NULL) {
        perror("malloc failed");
        pclose(fp);
        return NULL;
    }

    // 读取命令输出
    size_t total_read = 0;
    size_t size = BUFFER_SIZE;
    char buffer[BUFFER_SIZE];
    
    while (fgets(buffer, BUFFER_SIZE, fp) != NULL) {
        size_t len = strlen(buffer);
        if (total_read + len + 1 > size) {
            size *= 2;
            char* new_output = (char*) realloc(output, size);
            if (new_output == NULL) {
                perror("realloc failed");
                free(output);
                pclose(fp);
                return NULL;
            }
            output = new_output;
        }
        strcpy(output + total_read, buffer);
        total_read += len;
    }

    pclose(fp);
    OH_LOG_INFO(LOG_APP, "[CMD-SpacemiT] %s\n%s\n", command, output);
    return output;
}

// 从top命令输出中获取CPU使用率
double get_cpu_usage_from_top() {
    // 运行top命令获取CPU信息
    char* top_output = execute_command("top -b -n 1 | grep \"cpu\"");
    if (top_output == NULL) {
        free(top_output);
        return -1.0;
    }

    double cpu_usage = 0.0;
    char* line = strtok(top_output, "\n");
    
    if (line != NULL) {
        // 查找关键字段
        char n_cores = line[0];
        int n = atoi(&n_cores);
        char* id_ptr = strstr(line, "idle");
        float id = 0.0;
            
        // 从字符串中提取数值
        sscanf(id_ptr - 4, "%f", &id);

        // 计算CPU使用率 (100% - idle%)
        cpu_usage = (n * 100.0 - id) / n;
    }

    free(top_output);
    return cpu_usage;
}

// 从top命令输出中获取内存使用率
void get_mem_usage_from_top(int& mem_total, int& mem_used) {
    // 运行top命令获取内存信息
    char* top_output = execute_command("top -b -n 1 | grep \"Mem\"");
    if (top_output == NULL) {
        free(top_output);
        return;
    }

    char* line = strtok(top_output, "\n");
    
    if (line != NULL) {
        int count = 0;
        int* ptr = &mem_total;
        char* mem_ptr = strtok(line, "  ");
        while(count < 2 && mem_ptr != NULL){
            mem_ptr = strtok(NULL, "  ");
            if(strchr(mem_ptr, 'K')){
                sscanf(mem_ptr, "%d", ptr);
                count += 1;
                ptr = &mem_used;
            }
        }
        mem_total /= 1024;
        mem_used /= 1024;
    }

    free(top_output);
}

// 从df命令输出中获取磁盘使用率
void get_disk_usage_from_df(double& disk_total, double& disk_used) {
    // 运行df命令获取磁盘信息
    char* line = execute_command("df -h | grep /data/storage");
    if (line == NULL) {
        free(line);
        return;
    }
    
    if (line != NULL) {
        char filesystem[128], size[16], used[16], avail[16], use_percent[16], mounted_on[128];
        
        // 解析df输出行
        if (sscanf(line, "%s %s %s %s %s %s", 
                   filesystem, size, used, avail, use_percent, mounted_on) >= 5) {
            // 提取百分比值（去掉末尾的%）
            
            char* unit;
            disk_total = strtod(size, &unit);
            if (!strcmp(unit, "M"))
                disk_total /= 1024;
            disk_used = strtod(used, &unit);
            if (!strcmp(unit, "M"))
                disk_used /= 1024;
        }
    }

    free(line);
}

void get_interface(char* ifaces){
    // 已经获取过网络接口，清理链表重新获取
    if (iface_head) 
        free_iface();

    int count = 0;
     char* cmd_output = execute_command("ifconfig -S");
    if (cmd_output == NULL) {
        free(cmd_output);
        return;
    }

    char* line = strtok(cmd_output, "\n");
    interface* iface_tail;
    while (line) {
        // 跳过本地回环
        if (!strncmp(line, "lo", 2)) {
            line = strtok(NULL, "\n");
            continue;
        }
        
        char* end_of_name = strchr(line, ' ');
        if (end_of_name == NULL) {
            perror("parse line failed");
            return;
        }

        interface* iface = new interface();
        strncat(iface->name, line, end_of_name - line);
        OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] setting interface: %s\n", iface->name);
        strcat(ifaces, iface->name);
        strcat(ifaces, " ");

        if (iface_head == NULL) {
            iface_head = iface;
            iface_tail = iface_head;
        } else {
            iface_tail->next = iface;
            iface_tail = iface_tail->next;
        }

        count += 1;
        line = strtok(NULL, "\n");
    }

    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] get interfaces: %d\n", count);
}

void init_gateway(interface* iface) {
    char* cmd_output = execute_command("netstat -rn");
    if (cmd_output == NULL) {
        free(cmd_output);
        return;
    }

    char* line = strtok(cmd_output, "\n");
    line = strtok(NULL, "\n");
    line = strtok(NULL, "\n");
    while (line != NULL) {
        char* netstate_name = strrchr(line, ' ');
        netstate_name++;

        if (strcmp(netstate_name, iface->name)) {
            line = strtok(NULL, "\n");
            continue;
        }

        // 查找gateway位置
        char* tmp = line;
        bool reach_blankspace = false;
        bool reach_gateway = false;
        while (!(reach_blankspace && reach_gateway)){
            if (*tmp == ' ')
                reach_blankspace = true;
            if (reach_blankspace && *tmp != ' '){
                reach_gateway = true;
                break;
            }
            tmp++;
        }
        
        char* gateway = strtok(tmp, " ");
        strcpy(iface->gateway, gateway);
        break;
    }

    if (strlen(iface->gateway) == 0)
        strcpy(iface->gateway, "Parse gateway failed");
    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] gateway: %s\n", iface->gateway);
}

void init_hwaddr(interface* iface) {
    char cmd[32];
    sprintf(cmd, "ifconfig %s", iface->name);
    char* cmd_output = execute_command(cmd);
    if (cmd_output == NULL or strstr(cmd_output, "No such device")) {
        free(cmd_output);
        return;
    }

    char* line = strtok(cmd_output, "\n");
    char* hwaddr = strstr(line, "HWaddr ");
    if (hwaddr == NULL) {
        strcpy(iface->hwaddr, "Parse hwaddr failed");
        return;
    }

    hwaddr += 7;
    hwaddr = strtok(hwaddr, " ");
    strcpy(iface->hwaddr, hwaddr);
    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] hwaddr: %s\n", iface->hwaddr);
}

void init_ipv4(interface* iface) {
    char cmd[32];
    sprintf(cmd, "ifconfig %s", iface->name);
    char* cmd_output = execute_command(cmd);
    if (cmd_output == NULL or strstr(cmd_output, "No such device")) {
        free(cmd_output);
        return;
    }

    char* line = strtok(cmd_output, "\n");
    line = strtok(NULL, "\n");
    char* ipv4 = strstr(line, "inet addr:");
    if (ipv4 == NULL) {
        strcpy(iface->ipv4, "Parse ipv4 failed");
        return;
    }

    ipv4 += 10;
    ipv4 = strtok(ipv4, " ");
    strcpy(iface->ipv4, ipv4);
    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] set up ipv4: %s\n", iface->ipv4);
}

void init_ipv6(interface* iface) {
    char cmd[32];
    sprintf(cmd, "ifconfig %s", iface->name);
    char* cmd_output = execute_command(cmd);
    if (cmd_output == NULL or strstr(cmd_output, "No such device")) {
        free(cmd_output);
        return;
    }

    char* line = strtok(cmd_output, "\n");
    line = strtok(NULL, "\n");
    line = strtok(NULL, "\n");
    char* ipv6 = strstr(line, "inet6 addr: ");
    if (ipv6 == NULL) {
        strcpy(iface->ipv6, "Parse ipv6 failed");
        return;
    }

    ipv6 += 12;
    ipv6 = strtok(ipv6, "/");
    strcpy(iface->ipv6, ipv6);
    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] set up ipv6: %s\n", iface->ipv6);
}

void init_bytes(interface* iface) {
    char cmd[32];
    sprintf(cmd, "ifconfig %s", iface->name);
    char* cmd_output = execute_command(cmd);
    if (cmd_output == NULL or strstr(cmd_output, "No such device")) {
        free(cmd_output);
        return;
    }

    char* line_last;
    char* line = strtok(cmd_output, "\n");
    while (line) {
        line_last = line;
        line = strtok(NULL, "\n");
    }

    char* rx = strstr(line_last, "RX bytes:");
    char* tx = strstr(line_last, "TX bytes:");
    if (rx == NULL or tx == NULL)
        return;

    rx += 9;
    tx += 9;
    rx = strtok(rx, " ");
    tx = strtok(tx, "\n");
    iface->rx = atoi(rx);
    iface->tx = atoi(tx);
    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] set up bytes: %d %d\n", iface->rx, iface->tx);
}

void set_interface(interface* iface) {
    init_gateway(iface);
    init_hwaddr(iface);
    init_ipv4(iface);
    init_ipv6(iface);
    init_bytes(iface);
}

// 获取CPU核数
int get_cpu_core_count() {
    char* cmd_output = execute_command("ls /sys/devices/system/cpu/ | grep -E '^cpu[0-9]+$' | wc -l");
    if (cmd_output == NULL) {
        return -1;
    }
    
    int core_count = atoi(cmd_output);
    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] CPU core count: %d\n", core_count);
    return core_count;
}

// 获取CPU最大频率（单位：MHz）
int get_cpu_max_frequency() {
    char* cmd_output = execute_command("cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq");
    if (cmd_output == NULL) {
        return -1.0;
    }
    
    int freq = atol(cmd_output);
    free(cmd_output);
    OH_LOG_INFO(LOG_APP, "[CC-SpacemiT] CPU max frequency: %d Hz\n", freq);
    return freq;
}

static napi_value GetCPUUsage(napi_env env, napi_callback_info info){
    napi_value ret;
    char str[BUFFER_SIZE];
    snprintf(str, BUFFER_SIZE, "%.2f%%", get_cpu_usage_from_top());
    napi_create_string_utf8(env, str, strlen(str), &ret);

    return ret;
}

static napi_value GetMemUsage(napi_env env, napi_callback_info info){
    napi_value ret, total, used;
    int mem_total = -1, mem_used = -1;
    get_mem_usage_from_top(mem_total, mem_used);
    char str[BUFFER_SIZE];
    snprintf(str, BUFFER_SIZE, "%.2f%%(%d/%d MB)", 
        (double)mem_used/(double)mem_total*100, mem_used, mem_total);
    napi_create_string_utf8(env, str, strlen(str), &ret);
    return ret;
}

static napi_value GetDiskUsage(napi_env env, napi_callback_info info){
    napi_value ret;
    double disk_total = -1, disk_used = -1;
    get_disk_usage_from_df(disk_total, disk_used);
    char str[BUFFER_SIZE];
    snprintf(str, BUFFER_SIZE, "%.2f%%(%.2f/%.2f GB)", 
        disk_used/disk_total*100, disk_used, disk_total);
    napi_create_string_utf8(env, str, strlen(str), &ret);
    
    return ret;
}

static napi_value GetInterface(napi_env env, napi_callback_info info){
    napi_value ret;
    char interfaces[32] = "";
    get_interface(interfaces);
    napi_create_string_utf8(env, interfaces, strlen(interfaces),&ret);
    return ret;
}

static napi_value InitInterface(napi_env env, napi_callback_info info){
    size_t argc = 1;
    napi_value args[1] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
    
    char value0[16] = "";
    size_t result;
    napi_get_value_string_utf8(env, args[0], value0, 16, &result);
    
    init_interface(value0);
    
    return NULL;
}

static napi_value GetGateway(napi_env env, napi_callback_info info){
    napi_value ret;
    char* param;
    if (iface_select && iface_select->gateway){
        param = iface_select->gateway;
    } else
        param =  "";

    napi_create_string_utf8(env, param, strlen(param),&ret);
    return ret;
}
static napi_value GetHWaddr(napi_env env, napi_callback_info info){
    napi_value ret;
    char* param;
    if (iface_select && iface_select->hwaddr){
        param = iface_select->hwaddr;
    } else
        param =  "";

    napi_create_string_utf8(env, param, strlen(param),&ret);
    return ret;
}
static napi_value GetIPV4(napi_env env, napi_callback_info info){
    napi_value ret;
    char* param;
    if (iface_select && iface_select->ipv4){
        param = iface_select->ipv4;
    } else
        param =  "";

    napi_create_string_utf8(env, param, strlen(param),&ret);
    return ret;
}

static napi_value GetIPV6(napi_env env, napi_callback_info info){
    napi_value ret;
    char* param;
    if (iface_select && iface_select->ipv6){
        param = iface_select->ipv6;
    } else
        param =  "";

    napi_create_string_utf8(env, param, strlen(param),&ret);
    return ret;
}

static napi_value GetRX(napi_env env, napi_callback_info info){
    napi_value ret;
    unsigned int param;
    if (iface_select && iface_select->rx){
        param = iface_select->rx;
    } else
        param =  -1;

    napi_create_int32(env, param, &ret);
    return ret;
}

static napi_value GetTX(napi_env env, napi_callback_info info){
    napi_value ret;
    unsigned int param;
    if (iface_select && iface_select->tx){
        param = iface_select->tx;
    } else
        param =  -1;

    napi_create_int32(env, param, &ret);
    return ret;
}

static napi_value GetCPUCoreCount(napi_env env, napi_callback_info info){
    napi_value ret;
    int core_count = get_cpu_core_count();
    napi_create_int32(env, core_count, &ret);
    return ret;
}

static napi_value GetCPUMaxFreq(napi_env env, napi_callback_info info){
    napi_value ret;
    int max_freq = get_cpu_max_frequency();
    char str[BUFFER_SIZE];
    napi_create_int32(env, max_freq, &ret);
    return ret;
}

static napi_value Add(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;

}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getCPUUsage", nullptr, GetCPUUsage, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getMemUsage", nullptr, GetMemUsage, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getDiskUsage", nullptr, GetDiskUsage, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getInterface", nullptr, GetInterface, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "initInterface", nullptr, InitInterface, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getGateway", nullptr, GetGateway, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getHWaddr", nullptr, GetHWaddr, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getIPV4", nullptr, GetIPV4, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getIPV6", nullptr, GetIPV6, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getRX", nullptr, GetRX, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getTX", nullptr, GetTX, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getCPUCoreCount", nullptr, GetCPUCoreCount, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "getCPUMaxFreq", nullptr, GetCPUMaxFreq, nullptr, nullptr, nullptr, napi_default, nullptr },
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
